package com.example.demo.service.impl;

import com.example.demo.dto.ErrorCode;
import com.example.demo.dto.ResponseValue;
import com.example.demo.dto.common.ConsultHistoryModel;
import com.example.demo.entity.Consultant;
import com.example.demo.entity.User;
import com.example.demo.entity.relation.ConsultRecord;
import com.example.demo.enums.Role;
import com.example.demo.exception.EntityAlreadyExistException;
import com.example.demo.exception.EntityNotExistException;
import com.example.demo.redis.RedisKey;
import com.example.demo.repository.dao.ConsultantDao;
import com.example.demo.repository.dao.UserDao;
import com.example.demo.repository.dao.relation.ConsultRecordDao;
import com.example.demo.service.UserService;
import com.example.demo.utils.EntityUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.transaction.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class UserServiceImpl implements UserService {
    private final UserDao userDao;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ConsultRecordDao consultRecordDao;
    private final ConsultantDao consultantDao;

    public UserServiceImpl(UserDao userDao, RedisTemplate<String, Object> redisTemplate, ConsultRecordDao consultRecordDao,
                           ConsultantDao consultantDao){
        this.userDao = userDao;
        this.redisTemplate = redisTemplate;
        this.consultRecordDao = consultRecordDao;
        this.consultantDao = consultantDao;
    }

    @Override
    public User getUserByNumber(String number) throws EntityNotExistException {
        if(number.length()!=11){
            return null;
        }
        User user = userDao.findUserByPhoneNumber(number);
        if(user != null){
            return user;
        }
        throw new EntityNotExistException();
    }

    @Override
    public String addUser(User user) throws EntityAlreadyExistException{
        User oldUser = userDao.findUserByPhoneNumber(user.getPhoneNumber());
        if(oldUser!=null) return oldUser.getPhoneNumber();
        user.setId(UUID.randomUUID().toString());
        user.setPassword("123456");
        byte[] bytes = DigestUtils.md5Digest(user.getPassword().getBytes(StandardCharsets.UTF_8));
        user.setPassword(new String(bytes, StandardCharsets.UTF_8));
        user.setIsAdmin("0");
        userDao.save(user);
        return user.getPhoneNumber();
    }

    @Override
    public void deleteUser(String number) {
        int count = userDao.deleteByPhoneNumber(number);
    }

    @Override
    public void deleteUserBatch(List<String> numbers) {
        userDao.deleteByPhoneNumberIn(numbers);
    }

    @Override
    public void updateUser(String number, User user) throws EntityNotExistException, IllegalAccessException {
        User oldUser = this.getUserByNumber(number);
        if(!user.getUrgentName().equals("")) oldUser.setUrgentName(user.getUrgentName());
        //EntityUtils.transEmptyToNull(user);
        if(user.getPassword()!=null && !user.getPassword().equals("")){
            byte[] bytes = DigestUtils.md5Digest(user.getPassword().getBytes(StandardCharsets.UTF_8));
            user.setPassword(new String(bytes, StandardCharsets.UTF_8));
        }
        oldUser.setName(user.getName());
        oldUser.setUrgentNumber(user.getUrgentNumber());
        oldUser.setUrgentName(user.getUrgentName());
        userDao.save(oldUser);
    }

    @Override
    public void updateUserRole(String number, Role role) throws EntityNotExistException {
        User user = this.getUserByNumber(number);
        user.setRole(role);
        userDao.save(user);
    }

    @Override
    public List<User> getUserList(List<String> numbers) {
        return userDao.findByPhoneNumberIn(numbers);
    }

    @Override
    public Map<String, Object> login(String number, String inputCode) throws EntityNotExistException {
        if(userDao.findUserByPhoneNumber(number)==null){
            throw new EntityNotExistException("用户不存在");
        }
        if(inputCode.length()==0){
            redisTemplate.opsForValue().set(RedisKey.USER_TOKEN.replace("{token}", number), 1, 30, TimeUnit.MINUTES);
            Map<String, Object> m = new HashMap<>();
            m.put("number", number);
            redisTemplate.opsForSet().add(RedisKey.USER_ONLINE_SET, number);
            return m;
        }
        String redisKey = RedisKey.USER_CODE.replace("{number}", number);
        String code = (String)redisTemplate.opsForValue().get(redisKey);
        if(code!=null && code.equals(inputCode)){
            redisTemplate.opsForValue().set(RedisKey.USER_TOKEN.replace("{token}", number), 1, 30, TimeUnit.MINUTES);
            Map<String, Object> m = new HashMap<>();
            m.put("number", number);
            redisTemplate.opsForSet().add(RedisKey.USER_ONLINE_SET, number);
            return m;
        }
        return null;
    }

    @Override
    public Map<String, Object> loginForAdmin(String phoneNumber, String password) throws EntityNotExistException {
        User user = this.getUserByNumber(phoneNumber);
        byte[] inputBytes = DigestUtils.md5Digest(password.getBytes(StandardCharsets.UTF_8));
        String inputPassword = new String(inputBytes, StandardCharsets.UTF_8);
        if(inputPassword.equals(user.getPassword())){
            Map<String, Object> m = new HashMap<>();
            m.put("number", phoneNumber);
            redisTemplate.opsForValue().set(RedisKey.USER_TOKEN.replace("{userId}", phoneNumber), 1);
            return m;
        }
        return null;
    }

    @Override
    public void logout(String number) {
        redisTemplate.delete(RedisKey.USER_TOKEN.replace("{userId}", number));
    }

    @Override
    public List<ConsultRecord> getConsultRecords(String number) {
        return consultRecordDao.findAllByUserId(number);
    }

    @Override
    public void evaluateConsult(ConsultHistoryModel model) throws EntityNotExistException {
        String id = model.getId();
        Optional<ConsultRecord> optional = consultRecordDao.findById(id);
        if(!optional.isPresent()){
            throw new EntityNotExistException("咨询历史不存在");
        }
        ConsultRecord record = optional.get();
        record.setEvaluateScore(model.getEvaluateScore());
        record.setEvaluateText(model.getEvaluateText());
        record.setHadEvaluated("1");
        consultRecordDao.save(record);
    }

    @Override
    public void banUser(String number) throws EntityNotExistException {
        Optional<User> optional = userDao.findById(number);
        if(optional.isPresent()){
            User user = optional.get();
            user.setIsValid("0");
            userDao.save(user);
        }
        throw new EntityNotExistException("用户不存在");
    }

    @Override
    public List<User> getAllUsers() {
        List<User> users = userDao.findAll();
        return users;
    }

    @Override
    public ConsultHistoryModel addConsultHistory(ConsultHistoryModel model) throws EntityNotExistException {
        User user = this.getUserByNumber(model.getUser().getPhoneNum());
        Consultant consultant = consultantDao.getConsultantByPhoneNumber(model.getConsultant().getPhoneNum());
        if(user==null || consultant==null) return null;
        ConsultRecord record = new ConsultRecord();
        record.setHadEvaluated("0");
        record.setEvaluateText(model.getEvaluateText());
        record.setEvaluateScore(model.getEvaluateScore());
        record.setId(UUID.randomUUID().toString());
        record.setConsultType(model.getConsultType());
        record.setDuration(model.getDuration());
        record.setConsultantId(consultant.getId());
        record.setUserId(model.getUser().getPhoneNum());
        record.setTime(model.getTime());
        record.setUserName(user.getName());
        record.setConsultantName(consultant.getName());
        consultRecordDao.save(record);
        return model;
    }
}
